package com.lmy.androidcustomview.touch.drag

import android.content.Context
import android.util.AttributeSet
import android.view.DragEvent
import android.view.View
import android.view.ViewGroup
import androidx.core.view.children
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import java.util.*

/**
 * @author lmy
 * @功能:网格布局 拖拽排序功能
 * @Creat 2/15/21 1:45 PM
 * @Compony 465008238@qq.com
 */

class DragListenerGridView(context: Context?, attrs: AttributeSet?) : ViewGroup(context, attrs) {
    private var dragListener: OnDragListener = HenDragListener()
    private var draggedView: View? = null
    private var orderedChildren: MutableList<View> = ArrayList()
    private val COLUMNS = 2
    private val ROWS = 3

    init {
        isChildrenDrawingOrderEnabled = true
    }


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val specWidth = MeasureSpec.getSize(widthMeasureSpec)
        val specHeight = MeasureSpec.getSize(heightMeasureSpec)
        val childWidth = specWidth / COLUMNS
        val childHeight = specHeight / ROWS
        measureChildren(
            MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
            MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)
        )
        setMeasuredDimension(specWidth, specHeight)
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        var childLeft: Int
        var childTop: Int
        val childWidth = width / COLUMNS
        val childHeight = height / ROWS
        /**
         * 遍历子View并设置子View的位置
         * 因为我们横向只有两列 横向偏移距离=index%2*子view的宽度  只可能是0或者1
         * 纵向就需要index/2*子view的宽度
         */
        for ((index, child) in children.withIndex()) {
            childLeft = index % 2 * childWidth
            childTop = index / 2 * childHeight
            //
            /**
             * 这里把所有的子View都放在左上角通过
             * translation来进行偏移来改变他们的位置
             */
            child.layout(0, 0, childWidth, childHeight)
            child.translationX = childLeft.toFloat()
            child.translationY = childTop.toFloat()
        }
    }


    /**
     *界面完成初始化以后 遍历子View添加长按事件 并设置拖拽功能
     */
    override fun onFinishInflate() {
        super.onFinishInflate()
        for (child in children) {
            orderedChildren.add(child) // 初始化位置
            child.setOnLongClickListener { v ->
                draggedView = v
                //设置拖拽
                v.startDrag(null, DragShadowBuilder(v), v, 0)
                false
            }
            //设置拖拽监听器 所有子View都设置类拖拽监听 一个被拖拽都会收到监听回调
            child.setOnDragListener(dragListener)
        }
    }


    /**
     * 拖拽事件的回调
     */
    override fun onDragEvent(event: DragEvent?): Boolean {
        return super.onDragEvent(event)
    }

    /**
     *重新排序View的代码
     */
    private fun sort(targetView: View) {
        var draggedIndex = -1
        var targetIndex = -1
        for ((index, child) in orderedChildren.withIndex()) {
            if (targetView === child) {
                targetIndex = index
            } else if (draggedView === child) {
                draggedIndex = index
            }
        }
        orderedChildren.removeAt(draggedIndex)
        orderedChildren.add(targetIndex, draggedView!!)
        var childLeft: Int
        var childTop: Int
        val childWidth = width / COLUMNS
        val childHeight = height / ROWS
        for ((index, child) in orderedChildren.withIndex()) {
            childLeft = index % 2 * childWidth
            childTop = index / 2 * childHeight
            //移动View动画
            child.animate()
                .translationX(childLeft.toFloat())
                .translationY(childTop.toFloat())
                .setDuration(150)
        }
    }

    /**
     * 自定义的继承OnDragListener接口类
     * 拖拽监听器
     */
    private inner class HenDragListener : OnDragListener {
        override fun onDrag(v: View, event: DragEvent): Boolean {
            /**
             *
             */
            when (event.action) {
                /**
                 * 因为所有View都会收到这个事件 所以需要判断当前拖拽的View是不是要隐藏的View
                 * event.localState 获取拖拽传递来的数据
                 * 和当前拖拽的View是不是同一个
                 */
                DragEvent.ACTION_DRAG_STARTED -> if (event.localState === v) {

                    v.visibility = View.INVISIBLE
                }
                /**
                 * 触摸到某个View的区域内
                 * 这里需要判断是不是移动到来自身的View中 自身则不处理移动的逻辑
                 */
                DragEvent.ACTION_DRAG_ENTERED -> if (event.localState !== v) {
                    sort(v)
                }
                /**
                 * 触摸离开某个View的区域内
                 */
                DragEvent.ACTION_DRAG_EXITED -> {
                }
                /**
                 *松手的时候需要把View恢复隐藏
                 */
                DragEvent.ACTION_DRAG_ENDED -> if (event.localState === v) {
                    v.visibility = View.VISIBLE
                }
            }
            return true
        }
    }

}
